#pragma once
#include "engine/platform/shader.h"
#include "engine/renderer/mesh/sprite.h"
#include <glm/glm.hpp>
#include <unordered_map>
#include "engine/core/camera2d.h"

namespace kanon
{
    struct SpriteVertex
    {
        glm::vec2 pos;
        glm::vec4 color;
        glm::vec2 uv;
        float texture_slot;
    };

    struct SpriteBatch
    {
    private:
        friend class SpriteRenderer;
        uint32_t vao = -1;
        uint32_t vbo = -1;
        uint32_t ibo = -1;

        uint32_t max_vertices = 0;
        uint32_t max_indices = 0;
        uint32_t num_vertices = 0;
        uint32_t num_indices = 0;

        uint32_t max_texture_slots = 16;
        uint32_t next_texture_slot = 0;
        std::unordered_map<uint32_t, uint32_t> texture_id2slot;

        SpriteVertex* vertex_base;
        uint32_t* index_base;

    public:
        SpriteBatch(uint32_t max_sprites);
        ~SpriteBatch();
        void Begin();
        void End();
        
        bool Submit(const SpriteQuad& sprite, const glm::mat4& transform);
    };

    class SpriteRenderer
    {
    private:
        const uint32_t MAX_SPRITES = 50000;

        std::shared_ptr<Shader> shader = nullptr;
        std::shared_ptr<SpriteBatch> batch = nullptr;
        std::shared_ptr<Camera2d> camera = nullptr;

    public:
        SpriteRenderer();
        ~SpriteRenderer() {}

        bool Submit(const SpriteQuad& sprite);
        bool Submit(const SpriteQuad& sprite, const glm::mat4& transform);

        void SetCamera(const std::shared_ptr<Camera2d>& cam);
        void Begin();
        void End();
        void Flush();
    };
}
